package vcsn;

import java.io.File;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.eclipse.core.resources.*;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jgit.diff.DiffEntry;

import vcsn.entities.AddCastingOperation;
import vcsn.entities.AddCommentOperation;
import vcsn.entities.CommitPatch;
import vcsn.entities.ConflictOperation;
import vcsn.entities.DropInterfaceTypeOperation;
import vcsn.entities.RefineParameterOperation;
import vcsn.entities.RelationMapDiff;
import vcsn.entities.RelationMapDiff.EntityType;
import vcsn.entities.RelationMapDiff.Status;
import vcsn.entities.RemoveKeyWordOperation;
import vcsn.entities.RenameOperation;
import vcsn.utils.ExportImportHandler;

public class RelationMapConflictDetector{
	public class Visitor extends ASTVisitor{
		public CompilationUnit unit;
		public String sourceFileName;		
		public List<RelationMapDiff> relationMapDiff;
		public List<ConflictOperation> conflictList;
		public int conflictsCount;
		private String elementQualifiedName;
		
		public Visitor(List<RelationMapDiff> incomingRelationMapDiff, CompilationUnit unit, String elementName){
			relationMapDiff = incomingRelationMapDiff;
			conflictsCount = 0;
			sourceFileName = elementName;
			this.unit = unit;
			conflictList = new ArrayList<ConflictOperation>();
		}
		
		@Override
		public boolean visit(SimpleName node){
			if (!node.isDeclaration()) {
				final IBinding nodeBinding = node.resolveBinding();
				if (nodeBinding instanceof IVariableBinding
						&& ((IVariableBinding) nodeBinding).getDeclaringClass() != null) {
					for(RelationMapDiff diffEntry : relationMapDiff){
						if(diffEntry.entityType == EntityType.VARIABLE
								&& diffEntry.entityIdentity.equals(((IVariableBinding)nodeBinding).getDeclaringClass().getQualifiedName() + "." + ((IVariableBinding)nodeBinding).getName())
								&& diffEntry.entityStatus == Status.REMOVE){
							RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
							if(relatedDiffEntry != null){
								if(!relatedDiffEntry.entityIdentity.equals(diffEntry.entityIdentity)){
									RenameOperation c = new RenameOperation();
									c.setConflictLocatedFileName(sourceFileName);
									c.setConflictLocatedPosition(node.getStartPosition());
									c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
									c.setOriginIdentifier(nodeBinding.getName().toString());
									c.setModifiedIdentifier(relatedDiffEntry.entityIdentity);
									conflictList.add(c);
									conflictsCount++;
								}
								if(!relatedDiffEntry.type.equals(diffEntry.type)){
									AddCastingOperation c = new AddCastingOperation();
									c.setConflictLocatedFileName(sourceFileName);
									c.setConflictLocatedPosition(node.getStartPosition());
									c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
									c.setCastToType(diffEntry.type);
									c.setOriginIdentifier(nodeBinding.getName().toString());
									c.setRefinedIdentifier(relatedDiffEntry.entityIdentity);
									conflictList.add(c);
									conflictsCount++;
								}
								if(relatedDiffEntry.modifier != diffEntry.modifier){
									if(!Modifier.isPublic(relatedDiffEntry.modifier)){
										AddCommentOperation c = new AddCommentOperation();
										c.setConflictLocatedFileName(sourceFileName);
										c.setConflictLocatedPosition(node.getStartPosition());
										c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
										c.setCommentString("modifier is changed, this statement no longer be able to be executed");
										conflictList.add(c);
										conflictsCount++;
									}
								}
							}else{
								AddCommentOperation c = new AddCommentOperation();
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(node.getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setCommentString("variable is removed, this statement no longer be able to be executed");
								conflictList.add(c);
								conflictsCount++;
							}
							
						}
					}
//					ITypeBinding declaringTypeBinding = ((IVariableBinding) nodeBinding).getDeclaringClass();
//					if( declaringTypeBinding != null){
//						//TODO: 
//						System.out.println("element name: " + this.elementQualifiedName);
//						System.out.println("parent name: " + declaringTypeBinding.getQualifiedName());
//						System.out.println("Node Name : " + nodeBinding.getName());
//					}
				}
			}
			return true;
		}
		
		@Override
		public boolean visit(FieldAccess node){
			IVariableBinding variableBind = node.resolveFieldBinding();
			for(RelationMapDiff diffEntry : relationMapDiff){
				if(diffEntry.entityType == EntityType.VARIABLE
						&& diffEntry.entityIdentity.equals(variableBind.getDeclaringClass().getQualifiedName() + "." + variableBind.getName())
						&& diffEntry.entityStatus == Status.REMOVE){
					RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
					if(relatedDiffEntry != null){
						if(!relatedDiffEntry.entityIdentity.equals(diffEntry.entityIdentity)){
							RenameOperation c = new RenameOperation();
							c.setConflictLocatedFileName(sourceFileName);
							c.setConflictLocatedPosition(node.getName().getStartPosition());
							c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
							c.setOriginIdentifier(node.getName().toString());
							c.setModifiedIdentifier(relatedDiffEntry.entityIdentity);
							conflictList.add(c);
							conflictsCount++;
						}
						if(!relatedDiffEntry.type.equals(diffEntry.type)){
							AddCastingOperation c = new AddCastingOperation();
							c.setConflictLocatedFileName(sourceFileName);
							c.setConflictLocatedPosition(node.getStartPosition());
							c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
							c.setCastToType(diffEntry.type);
							c.setOriginIdentifier(node.getName().toString());
							c.setRefinedIdentifier(relatedDiffEntry.entityIdentity);
							conflictList.add(c);
							conflictsCount++;
						}
						if(relatedDiffEntry.modifier != diffEntry.modifier){
							if(!Modifier.isPublic(relatedDiffEntry.modifier)){
								AddCommentOperation c = new AddCommentOperation();
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(node.getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setCommentString("modifier is changed, this statement no longer be able to be executed");
								conflictList.add(c);
								conflictsCount++;
							}
						}
					}else{
						AddCommentOperation c = new AddCommentOperation();
						c.setConflictLocatedFileName(sourceFileName);
						c.setConflictLocatedPosition(node.getStartPosition());
						c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
						c.setCommentString("variable is removed, this statement no longer be able to be executed");
						conflictList.add(c);
						conflictsCount++;
					}
					
				}
			}
			return true;
		}
				
		@Override
		public boolean visit(MethodInvocation methodInvocation){
			IMethodBinding methodBind = methodInvocation.resolveMethodBinding();
			String qualifiedMethodSignature = methodBind.getDeclaringClass().getQualifiedName() + "." + methodBind.getName() + Config.separator;
			for(ITypeBinding parameterBind : methodBind.getParameterTypes()){
				qualifiedMethodSignature += parameterBind.getQualifiedName() + Config.separator;
			}
			for(RelationMapDiff diffEntry : relationMapDiff){
				if(diffEntry.entityType == EntityType.METHOD 
						&& diffEntry.entityIdentity.equals(qualifiedMethodSignature) 
						&& diffEntry.entityStatus == Status.REMOVE){
					RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
					if(relatedDiffEntry != null){
						String diffEntryIdentifier = diffEntry.entityIdentity.split(Config.separator)[0];
						String relatedDiffEntryIdentifier = relatedDiffEntry.entityIdentity.split(Config.separator)[0];
						if(!diffEntryIdentifier.equals(relatedDiffEntryIdentifier)){
							RenameOperation c = new RenameOperation();
							c.setConflictLocatedFileName(sourceFileName);
							c.setConflictLocatedPosition(methodInvocation.getName().getStartPosition());
							c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
							c.setOriginIdentifier(methodInvocation.getName().toString());
							c.setModifiedIdentifier(relatedDiffEntry.entityIdentity.split(Config.separator)[0]);
							conflictList.add(c);
							conflictsCount++;
						}
						String diffEntryParameterString = "";
						String relatedDiffEntryParameterString = "";
						
						/* record the index of every type of arguments occurred in method invocation.
						* The index of that argument will be used to get the corresponding argument expression.
						* the expression will place in the refined argument list by the order of appearance of the refined argument list.
						* Thus the parameter change can be handled. 
						*
						* P.S. -1 index represent a not exist argument in the origin argument list, 
						* the type may exist before but the number of arguments is larger than origin.
						* which means that type of argument has add one or more into that method.
						*/
						HashMap<String, List<Integer>> argPositionHash = new HashMap<String, List<Integer>>();
						HashMap<String, List<Integer>> refinedArgPositionHash = new HashMap<String, List<Integer>>();
						HashMap<String, Integer> argPositionHashHashCurrentIndexMap =  new HashMap<String, Integer>();
						HashMap<String, Integer> refinedArgPositionHashCurrentIndexMap =  new HashMap<String, Integer>();
						
						for(int i = 1; i < diffEntry.entityIdentity.split(Config.separator).length;i++){
							String key = diffEntry.entityIdentity.split(Config.separator)[i];
							diffEntryParameterString += key + Config.separator;
							List<Integer> positionList = new ArrayList<Integer>();
							if(argPositionHash.containsKey(key)){
								positionList = argPositionHash.get(key);
							}
							positionList.add(i - 1);
							argPositionHash.put(key, positionList);
						}
						for(int i = 1; i < relatedDiffEntry.entityIdentity.split(Config.separator).length;i++){
							String key = relatedDiffEntry.entityIdentity.split(Config.separator)[i];
							relatedDiffEntryParameterString += key + Config.separator;
							if(!refinedArgPositionHash.containsKey(key)){
								List<Integer> positionList = new ArrayList<Integer>();
								positionList.add(-1);
								refinedArgPositionHash.put(key, positionList);
							}
						}
						for(String key : refinedArgPositionHash.keySet()){
							refinedArgPositionHashCurrentIndexMap.put(key, 0);
						}
						for(String key : argPositionHash.keySet()){
							argPositionHashHashCurrentIndexMap.put(key, 0);
						}
						
						// following action is to match argument types that still existing in new argument list and obtain the position of argument expression in the origin argument list.
						if(!diffEntryParameterString.equals(relatedDiffEntryParameterString)){
							for(int i = 0; i < relatedDiffEntryParameterString.split(Config.separator).length; i++){
								String parameterType = relatedDiffEntryParameterString.split(Config.separator)[i];
								if(argPositionHash.containsKey(parameterType)){
									if(argPositionHashHashCurrentIndexMap.get(parameterType) < argPositionHash.get(parameterType).size()){
										Integer argPosition = argPositionHash.get(parameterType).get(argPositionHashHashCurrentIndexMap.get(parameterType));
										List<Integer> argPositionList = refinedArgPositionHash.get(parameterType);
										if(argPositionList.get(0) < 0){
											argPositionList.set(0, argPosition);
										}else{
											argPositionList.add(argPosition);
										}
										refinedArgPositionHash.put(parameterType, argPositionList);
										argPositionHashHashCurrentIndexMap.put(parameterType, argPositionHashHashCurrentIndexMap.get(parameterType) + 1);
									}else{
										List<Integer> argPositionList = refinedArgPositionHash.get(parameterType);
										if(argPositionList.get(argPositionList.size() - 1) >= 0){
											argPositionList.add(-1);
											refinedArgPositionHash.put(parameterType, argPositionList);
										}
									}
								}
							}
							/* following action is try to obtain the argument expression from the index given by refinedArgumentExpressionList and bind into the refinedArgumentExpressionList
							* if the refined method contains no parameter, refinedArgumentExpressionList would be null.
							* if the parameter is new added, the index should be -1, 
							* and refinedArgPositionHashCurrentIndexMap pointing to the corresponding argument index in refinedArgumentExpressionList would not increment to next position.
							*/
							String[] refinedArgumentExpressionList = null;
							if(!relatedDiffEntryParameterString.isEmpty()){
								refinedArgumentExpressionList = new String[relatedDiffEntryParameterString.split(Config.separator).length];
								for(int i = 0; i < relatedDiffEntryParameterString.split(Config.separator).length; i++){
									String keyArgumentType = relatedDiffEntryParameterString.split(Config.separator)[i];
									int argPosition = refinedArgPositionHash.get(keyArgumentType).get(refinedArgPositionHashCurrentIndexMap.get(keyArgumentType));
									if(argPosition >= 0 ){
										refinedArgumentExpressionList[i] = ((Expression)methodInvocation.arguments().get(argPosition)).toString().trim();
										refinedArgPositionHashCurrentIndexMap.put(keyArgumentType, refinedArgPositionHashCurrentIndexMap.get(keyArgumentType) + 1);
									}else{
										refinedArgumentExpressionList[i] = getDefaultValue(keyArgumentType);
									}
								}
							}
							RefineParameterOperation c = new RefineParameterOperation();
							c.setConflictLocatedFileName(sourceFileName);
							c.setConflictLocatedPosition(methodInvocation.getName().getStartPosition() + methodInvocation.getName().getLength());
							c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
							c.setArgumentListLength((methodInvocation.getStartPosition() + methodInvocation.getLength()) - c.getConflictLocatedPosition());
							c.setRefinedArgumentList(refinedArgumentExpressionList);
							conflictList.add(c);
							conflictsCount++;
						}
						if(!diffEntry.type.equals(relatedDiffEntry.type)){
							AddCastingOperation c = new AddCastingOperation();
							c.setConflictLocatedFileName(sourceFileName);
							c.setConflictLocatedPosition(methodInvocation.getStartPosition());
							c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
							c.setCastToType(diffEntry.type);
							c.setOriginIdentifier(methodInvocation.getName().toString());
							c.setRefinedIdentifier(relatedDiffEntry.entityIdentity);
							conflictList.add(c);
							conflictsCount++;
						}
					}else{
						AddCommentOperation c = new AddCommentOperation();
						c.setConflictLocatedFileName(sourceFileName);
						c.setConflictLocatedPosition(methodInvocation.getStartPosition());
						c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
						c.setCommentString("method signature is changed and cannot be handled by vcsn, this statement no longer be able to be executed");
						conflictList.add(c);
						conflictsCount++;
					}
				}
//				for(ITypeBinding argumentBind : methodBind.getTypeArguments()){
//					if(diffEntry.entityType == EntityType.CLASS 
//							&& diffEntry.entityIdentity.equals(argumentBind.getQualifiedName())
//							&& diffEntry.entityStatus == Status.REMOVE){
////						RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
////						if(relatedDiffEntry != null){
////							
////						}else{
////							
////						}
//						AddCommentOperation c = new AddCommentOperation();
//						c.setConflictLocatedFileName(sourceFileName);
//						c.setConflictLocatedPosition(unit.getLineNumber(methodInvocation.getStartPosition()));
//						c.setCommentString("argument type is removed, this statement no longer be able to be executed");
//						conflictList.add(c);
//						conflictsCount++;
//					}
//				}
				if(diffEntry.entityType == EntityType.CLASS 
						&& diffEntry.entityIdentity.equals(methodBind.getReturnType().getQualifiedName())
						&& diffEntry.entityStatus == Status.REMOVE){
					AddCommentOperation c = new AddCommentOperation();
					c.setConflictLocatedFileName(sourceFileName);
					c.setConflictLocatedPosition(unit.getLineNumber(methodInvocation.getStartPosition()));
					c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
					c.setCommentString("returned type is removed, this statement no longer be able to be executed");
					conflictList.add(c);
					conflictsCount++;
				}
			}
			return true;
		}
		
		@Override
		public boolean visit(TypeDeclaration typeDeclaration){
			
			ITypeBinding typeBind = typeDeclaration.resolveBinding();
			this.elementQualifiedName = typeBind.getQualifiedName();
				Type superClassType = typeDeclaration.getSuperclassType();
				if(superClassType != null){
					ITypeBinding superClassTypeBind = superClassType.resolveBinding();
					for(RelationMapDiff diffEntry : relationMapDiff){
						if(diffEntry.entityType == EntityType.CLASS 
								&& diffEntry.entityIdentity.equals(superClassTypeBind.getQualifiedName())
								&& diffEntry.entityStatus == Status.REMOVE){
							RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
							if(relatedDiffEntry != null){
								RenameOperation c = new RenameOperation();
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(superClassType.getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setOriginIdentifier(superClassTypeBind.getName());
								c.setModifiedIdentifier(relatedDiffEntry.entityIdentity);
								conflictList.add(c);
								conflictsCount++;
							}else{
								//TODO: add a drop superClass operation
								RemoveKeyWordOperation c = new RemoveKeyWordOperation("extends");
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(superClassType.getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setFirstParameterStartingPosition(superClassType.getStartPosition());
								c.setLastParameterEndingPosition((superClassType.getStartPosition() + superClassType.getLength()));
								conflictList.add(c);
								conflictsCount++;
							}
						}
					}
				}
				if(typeDeclaration.superInterfaceTypes().size() > 0){
					int counter = 0;
					for(int i = 0; i < typeDeclaration.superInterfaceTypes().size(); i++){
						org.eclipse.jdt.core.dom.Type interfaceType = (org.eclipse.jdt.core.dom.Type) typeDeclaration.superInterfaceTypes().get(i);
						ITypeBinding interfaceBind = interfaceType.resolveBinding();
						for(RelationMapDiff diffEntry : relationMapDiff){
							if(diffEntry.entityType == EntityType.CLASS 
									&& diffEntry.entityIdentity.equals(interfaceBind.getQualifiedName()) 
									&& diffEntry.entityStatus.equals(RelationMapDiff.Status.REMOVE)){
								counter++;
							}
						}
					}
					if(counter == typeDeclaration.superInterfaceTypes().size()){
						RemoveKeyWordOperation c = new RemoveKeyWordOperation("implements");
						c.setConflictLocatedFileName(sourceFileName);
						c.setConflictLocatedPosition(((org.eclipse.jdt.core.dom.Type)typeDeclaration.superInterfaceTypes().get(0)).getStartPosition());
						c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
						c.setFirstParameterStartingPosition(((org.eclipse.jdt.core.dom.Type)typeDeclaration.superInterfaceTypes().get(0)).getStartPosition());
						c.setLastParameterEndingPosition((((org.eclipse.jdt.core.dom.Type)typeDeclaration.superInterfaceTypes().get(typeDeclaration.superInterfaceTypes().size() - 1)).getStartPosition()) + ((org.eclipse.jdt.core.dom.Type)typeDeclaration.superInterfaceTypes().get(typeDeclaration.superInterfaceTypes().size() - 1)).getLength());
						conflictList.add(c);
						conflictsCount++;
					}else{
						for(int i = 0; i < typeDeclaration.superInterfaceTypes().size(); i++){
							org.eclipse.jdt.core.dom.Type interfaceType = (org.eclipse.jdt.core.dom.Type) typeDeclaration.superInterfaceTypes().get(i);
							ITypeBinding interfaceBind = interfaceType.resolveBinding();
							for(RelationMapDiff diffEntry : relationMapDiff){
								if(diffEntry.entityType == EntityType.CLASS 
										&& diffEntry.entityIdentity.equals(interfaceBind.getQualifiedName()) 
										&& diffEntry.entityStatus.equals(RelationMapDiff.Status.REMOVE)){
									RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
									if(relatedDiffEntry != null){
										RenameOperation c = new RenameOperation();
										c.setConflictLocatedFileName(sourceFileName);
										c.setConflictLocatedPosition(interfaceType.getStartPosition());
										c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
										c.setOriginIdentifier(diffEntry.entityIdentity);
										c.setModifiedIdentifier(relatedDiffEntry.entityIdentity);
										conflictList.add(c);
										conflictsCount++;
									}else{
										DropInterfaceTypeOperation c = new DropInterfaceTypeOperation();
										c.setConflictLocatedFileName(sourceFileName);
										c.setConflictLocatedPosition(interfaceType.getStartPosition());
										c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
										c.setIsLastParameter((i + 1 == typeDeclaration.superInterfaceTypes().size()));
										if(c.getIsLastParameter()){
											c.setIdentifierLength(interfaceType.getLength());
										}else{
											int length = ((Type)typeDeclaration.superInterfaceTypes().get(i + 1)).getStartPosition() - interfaceType.getStartPosition();
											c.setIdentifierLength(length);
											c.setNeedPadding(i == 0);
										}
										conflictList.add(c);
										conflictsCount++;
									}
									//						Conflict c = new Conflict();
									//						c.conflictLocatedFileName = sourceFileName;
									//						c.conflictLocatedLineNumber = unit.getLineNumber(interfaceType.getStartPosition());
									//						conflictList.add(c);
									//						conflictsCount++;
								}
							}
						}
					}
				}
				FieldDeclaration[] fieldDeclaration = typeDeclaration.getFields();
				for(int i = 0; i < fieldDeclaration.length; i++){
					ITypeBinding variableBind = fieldDeclaration[i].getType().resolveBinding();
					for(RelationMapDiff diffEntry : relationMapDiff){
						if(variableBind.isParameterizedType()){
							for(ITypeBinding argumenttypeBind : variableBind.getTypeArguments()){
								if(diffEntry.entityType == EntityType.CLASS
										&& diffEntry.entityIdentity.equals(argumenttypeBind.getQualifiedName())
										&& diffEntry.entityStatus == Status.REMOVE){
									//								RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
									//								if(relatedDiffEntry != null){
									//									if(diffEntry)
									//								}else{
									//									
									//								}
									AddCommentOperation c = new AddCommentOperation();
									c.setConflictLocatedFileName(sourceFileName);
									c.setConflictLocatedPosition(fieldDeclaration[i].getStartPosition());
									c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
									c.setCommentString("Variable Argument type is removed, this statement no longer be able to be executed");
									conflictList.add(c);
									conflictsCount++;
								}
							}
							if(diffEntry.entityType == EntityType.CLASS
									&& diffEntry.entityIdentity.equals(variableBind.getErasure().getQualifiedName())
									&& diffEntry.entityStatus == Status.REMOVE){
								//							RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
								//							if(relatedDiffEntry != null){
								//								
								//							}else{
								//								
								//							}
								AddCommentOperation c = new AddCommentOperation();
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(fieldDeclaration[i].getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setCommentString("Variable Generic type is removed, this statement no longer be able to be executed");
								conflictList.add(c);
								conflictsCount++;
							}
						}else if(variableBind.isArray()){
							if(diffEntry.entityType == EntityType.CLASS
									&& diffEntry.entityIdentity.equals(variableBind.getElementType().getQualifiedName())
									&& diffEntry.entityStatus == Status.REMOVE){
								//							RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
								//							if(relatedDiffEntry != null){
								//								
								//							}else{
								//								
								//							}
								AddCommentOperation c = new AddCommentOperation();
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(fieldDeclaration[i].getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setCommentString("Variable type is removed, this statement no longer be able to be executed");
								conflictList.add(c);
								conflictsCount++;
							}
						}else if(variableBind.isWildcardType()){
							if(diffEntry.entityType == EntityType.CLASS
									&& diffEntry.entityIdentity.equals(variableBind.getQualifiedName())
									&& diffEntry.entityStatus == Status.REMOVE){
								//							RelationMapDiff relatedDiffEntry = isRelatedEntry(diffEntry);
								//							if(relatedDiffEntry != null){
								//								
								//							}else{
								//								
								//							}
								AddCommentOperation c = new AddCommentOperation();
								c.setConflictLocatedFileName(sourceFileName);
								c.setConflictLocatedPosition(fieldDeclaration[i].getStartPosition());
								c.setConflictLocatedLineNumber(unit.getLineNumber(c.getConflictLocatedPosition()));
								c.setCommentString("Variable type is removed, this statement no longer be able to be executed");
								conflictList.add(c);
								conflictsCount++;
							}
						}
					}
				}
			return true;
		}
		
		public int getEstimatedConflictCount(){
			return conflictsCount;
		}
		
		public List<ConflictOperation> getConflictDetailedList(){
			return conflictList;
		}
		
		public RelationMapDiff isRelatedEntry(RelationMapDiff diffEntry){
			for(RelationMapDiff diffRef : relationMapDiff){
				if(diffRef.entityType != diffEntry.entityType){
					continue;
				}
				boolean isSignatureExist = true;
				String[] identityRef = diffRef.entityIdentity.split(";")[0].split(".");
				String[] identity = diffEntry.entityIdentity.split(";")[0].split(".");
				for(int i = 0; i < identityRef.length; i++){
					if(!identity[i].equals(identityRef[i])){
						isSignatureExist = false;
					}
				}
				if(isSignatureExist  
						&& diffRef.declarationLineNumber == diffEntry.declarationLineNumber
						&& diffRef.entityStatus != diffEntry.entityStatus){
					return diffRef;
				}
			}
			return null;
		}
		
		private String getDefaultValue(String dataType){
			if(dataType.equals("btye")){
				return "0";
			}else if(dataType.equals("short")){
				return "0";
			}else if(dataType.equals("int")){
				return "0";
			}else if(dataType.equals("long")){
				return "0L";
			}else if(dataType.equals("float")){
				return "0.0f";
			}else if(dataType.equals("double")){
				return "0.0d";
			}else if(dataType.equals("char")){
				return "\'u0000\'";
			}else if(dataType.equals("boolean")){
				return "false";
			}else{
				return "null";
			}
		}
	}
	
	private IJavaProject project;
	
	public RelationMapConflictDetector(IProject p, List<RelationMapDiff> incomingRelationMapDiff, CommitPatch incomingPatch) throws Exception{
		if (!p.isNatureEnabled("org.eclipse.jdt.core.javanature"))
			throw new Exception("cannot instant Comparer class");
		
		project = JavaCore.create(p);
		int conflictCounter = 0;
		
		for (IPackageFragment mypackage : project.getPackageFragments()) {
			if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
				for (ICompilationUnit unit : mypackage.getCompilationUnits()) {
					// Now calculate conflict in the AST for all ICompilationUnits
					CompilationUnit parse = parse(unit);
					Visitor visitor = new Visitor(incomingRelationMapDiff, parse, unit.getPath().toString());
					parse.accept(visitor);
					conflictCounter += visitor.getEstimatedConflictCount();
					incomingPatch.addRangedElementsIntoConflictList(visitor.getConflictDetailedList());
//					System.out.println("incomingCommitHash : " + incomingPatch.getPatchHash());
					System.out.println("Estimated number of conflicts will occur in Comilation unit : " +  unit.getElementName() + " / "+ visitor.getEstimatedConflictCount());
				}

			}

		}
		System.out.println("Estimated number of conflicts will occur in project : " +  conflictCounter);
		incomingPatch.setEstimatedConflict(conflictCounter);
		
//		ReceivedPatchView.getInstance().getContentProvider().setElement(existingPatchList);
	}
	
	private static CompilationUnit parse(ICompilationUnit unit) {
        ASTParser parser = ASTParser.newParser(AST.JLS4);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        parser.setSource(unit);
        parser.setResolveBindings(true);
        return (CompilationUnit) parser.createAST(null); // parse
    }
}
